package net.kazed.nextaction.database;

import java.util.Date;

import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.provider.BaseColumns;

/**
 * Task.
 */
public class Task {
    /**
     * The content:// style URL for this table
     */
    public static final Uri CONTENT_URI = Uri.parse("content://" + GtdAndroid.PACKAGE + "/task");
    public static final Uri CONTENT_BATCH_URI = Uri.parse("content://" + GtdAndroid.PACKAGE + "/taskBatch");
    public static final Uri TASK_COMPLETED_URI = Uri.parse("content://" + GtdAndroid.PACKAGE + "/task/completed");
    public static final Uri cTopTasksContentURI = Uri.parse("content://" + GtdAndroid.PACKAGE + "/topTasks");
    public static final Uri cInboxTasksContentURI = Uri.parse("content://" + GtdAndroid.PACKAGE + "/inboxTasks");
    public static final Uri cDueTasksContentURI = Uri.parse("content://" + GtdAndroid.PACKAGE + "/dueTasks");
    public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.nextaction.task";
    public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.nextaction.task";

    public static final Uri CONTENT_TIMER_URI = Uri.parse("content://" + GtdAndroid.PACKAGE + "/taskTimer");
    public static final String CONTENT_TIMER_ITEM_TYPE = "vnd.android.cursor.item/vnd.nextaction.tasktimer";
    
    public static class ContentItemType {
        public static final String TASK_AND_SUB_TASKS = "vnd.android.cursor.item/vnd.nextaction.taskAndSubTasks";
    };

    public static class ContentUri {
        public static final Uri TASK_AND_SUB_TASKS = Uri.parse("content://" + GtdAndroid.PACKAGE + "/taskAndSubTasks");
    };

    public static final String PARAMETER_TASK_ID = "parameter.taskId";
    public static final String SELECTED_PARENT_ID = "parentTaskId";

    // used by due tasks to determine query type
    public static final int DAY_MODE = 0;
    public static final int WEEK_MODE = 1;
    public static final int MONTH_MODE = 2;

    /**
     * The default sort order for this table
     */
    public static final String DEFAULT_SORT_ORDER = "created ASC";

    public static final String TABLE = "task";

    public static class Column {
        public static final String ID = BaseColumns._ID;
        public static final String DESCRIPTION = "description";
        public static final String DETAILS = "details";
        public static final String CONTEXT_ID = "contextId";
        public static final String PARENT_TASK_ID = "parentTaskId";
        public static final String CREATED_DATE = "created";
        public static final String MODIFIED_DATE = "modified";
        public static final String START_DATE = "startDate";
        public static final String DUE_DATE = "dueDate";
        public static final String DISPLAY_ORDER = "displayOrder";
        public static final String COMPLETE = "complete";
        public static final String TYPE = "type";
        public static final String STATUS = "status";
        public static final String NUMBER_OF_SUB_TASKS = "numberOfSubTasks";
        public static final String NUMBER_OF_ALL_SUB_TASKS = "numberOfAllSubTasks";
    }

    public static final String PROJECT_NAME = "project_name";
    public static final String PROJECT_DEFAULT_CONTEXT_ID = "project_default_context_id";
    public static final String PROJECT_ARCHIVED = "project_archived";
    public static final String COMPLETED_TRUE = "1";

    public static final String CONTEXT_NAME = "context_name";
    public static final String CONTEXT_COLOUR = "context_colour";
    public static final String CONTEXT_ICON = "context_icon";

    /** Projection for all the columns of a task. */
    public static final Projection FULL_PROJECTION = new Projection(new String[] { Column.ID, Column.DESCRIPTION, Column.DETAILS, Column.CONTEXT_ID,
                    Column.PARENT_TASK_ID, Column.CREATED_DATE, Column.MODIFIED_DATE, Column.START_DATE, Column.DUE_DATE, Column.DISPLAY_ORDER,
                    Column.COMPLETE, Column.TYPE, Column.STATUS, Column.NUMBER_OF_SUB_TASKS, Column.NUMBER_OF_ALL_SUB_TASKS });
    /** Projection with only ID */
    public static final Projection ID_PROJECTION = new Projection(new String[] { Column.ID });

    public static final String INBOX_SELECTION = Task.Column.CONTEXT_ID + " = 0 or "
        + Task.Column.CONTEXT_ID + " is null";
    public static final String SORT_ORDER = Task.Column.STATUS + " ASC, ifnull(" + Task.Column.DUE_DATE + ", date('now', '+12 month')) ASC, "
        + Task.Column.PARENT_TASK_ID + " DESC";

    private Integer id;
    private String description = "";
    private String details = "";
    private Integer contextId;
    private Integer parentTaskId;
    private Date created;
    private Date modified;
    private Date startDate;
    private Date dueDate;
    private Integer order;
    private Boolean complete;
    private TaskStatus status;
    private Integer numberOfSubTasks;
    private Integer numberOfAllSubTasks;

    /**
     * Constructor.
     */
    public Task() {
    }

    /**
     * Constructor.
     * @param id ID.
     * @param description Description.
     * @param details Notes.
     * @param contextId Context ID.
     * @param parentTaskId ID of parent task.
     * @param created Timestamp created.
     * @param modified Timestamp modified.
     * @param startDate Start date.
     * @param dueDate Due date.
     * @param order Ordering.
     * @param complete True if complete.
     * @param status Status.
     */
    public Task(Integer id, String description, String details, Integer contextId, Integer parentTaskId, Date created,
                    Date modified, Date startDate, Date dueDate, Integer order, Boolean complete, TaskStatus status) {
        this.id = id;
        this.description = description;
        this.details = details;
        this.contextId = contextId;
        this.parentTaskId = parentTaskId;
        this.created = created;
        this.modified = modified;
        this.startDate = startDate;
        this.dueDate = dueDate;
        this.order = order;
        this.complete = complete;
        this.status = status;
    }

    /**
     * Constructor.
     * @param description Description.
     * @param details Notes.
     * @param contextId Context ID.
     * @param parentTaskId ID of parent task.
     * @param created Timestamp created.
     * @param modified Timestamp modified.
     * @param startDate Start date.
     * @param dueDate Due date.
     * @param order Ordering.
     * @param complete True if complete.
     * @param status Status.
     */
    public Task(String description, String details, Integer contextId, Integer parentTaskId, Date created, Date modified,
                    Date startDate, Date dueDate, Integer order, Boolean complete, TaskStatus status) {
        this(null, description, details, contextId, parentTaskId, created, modified, startDate, dueDate, order, complete, status);
    }

    /**
     * Constructor.
     * @param cursor Database cursor.
     */
    public Task(Cursor cursor) {
        Projection projection = Task.FULL_PROJECTION;
        this.id = projection.getInteger(cursor, Task.Column.ID);
        this.description = projection.getString(cursor, Task.Column.DESCRIPTION, "");
        this.contextId = projection.getInteger(cursor, Task.Column.CONTEXT_ID);
        this.parentTaskId = projection.getInteger(cursor, Task.Column.PARENT_TASK_ID);
        this.complete = projection.getBoolean(cursor, Task.Column.COMPLETE);
        this.details = projection.getString(cursor, Task.Column.DETAILS, "");
        this.status = TaskStatus.getEnum(projection.getInteger(cursor, Task.Column.STATUS));
        this.startDate = projection.getDate(cursor, Task.Column.START_DATE);
        this.dueDate = projection.getDate(cursor, Task.Column.DUE_DATE);
        this.numberOfSubTasks = projection.getInteger(cursor, Task.Column.NUMBER_OF_SUB_TASKS);
        this.numberOfAllSubTasks = projection.getInteger(cursor, Task.Column.NUMBER_OF_ALL_SUB_TASKS);
    }

    /**
     * Copy attributes to values.
     * @param values Values of model attributes.
     */
    public void toValues(ContentValues values) {
        values.put(Column.DESCRIPTION, description);
        values.put(Column.DETAILS, details);
        values.put(Column.CONTEXT_ID, contextId);
        if (parentTaskId == null) {
            values.putNull(Column.PARENT_TASK_ID);
        } else {
            values.put(Column.PARENT_TASK_ID, parentTaskId);
        }
        if (status != null) {
            values.put(Column.STATUS, status.getType());
        }
        if (created != null) {
            values.put(Column.CREATED_DATE, created.getTime());
        }
        if (modified != null) {
            values.put(Column.MODIFIED_DATE, modified.getTime());
        }
        if (startDate == null) {
            values.putNull(Column.START_DATE);
        } else {
            values.put(Column.START_DATE, startDate.getTime());
        }
        if (dueDate == null) {
            values.putNull(Column.DUE_DATE);
        } else {
            values.put(Column.DUE_DATE, dueDate.getTime());
        }
        values.put(Column.DISPLAY_ORDER, order);
        if (complete) {
            values.put(Column.COMPLETE, 1);
        } else {
            values.putNull(Column.COMPLETE);
        }
        if (numberOfSubTasks == null) {
            values.putNull(Column.NUMBER_OF_SUB_TASKS);
        } else{
            values.put(Column.NUMBER_OF_SUB_TASKS, numberOfSubTasks);
        }
        if (numberOfAllSubTasks == null) {
            values.putNull(Column.NUMBER_OF_ALL_SUB_TASKS);
        } else{
            values.put(Column.NUMBER_OF_ALL_SUB_TASKS, numberOfAllSubTasks);
        }
    }

    /**
     * @return The id
     */
    public Integer getId() {
        return id;
    }

    /**
     * @param id The id to set
     */
    public void setId(Integer id) {
        this.id = id;
    }

    /**
     * @return The description
     */
    public String getDescription() {
        return description;
    }

    /**
     * @param description The description to set
     */
    public void setDescription(String description) {
        this.description = description;
    }

    /**
     * @return The details
     */
    public String getDetails() {
        return details;
    }

    /**
     * @param details The details to set
     */
    public void setDetails(String details) {
        this.details = details;
    }

    /**
     * @return The contextId
     */
    public Integer getContextId() {
        return contextId;
    }

    /**
     * @param contextId The contextId to set
     */
    public void setContextId(Integer contextId) {
        this.contextId = contextId;
    }

    /**
     * @return The parentTaskId
     */
    public Integer getParentTaskId() {
        return parentTaskId;
    }

    /**
     * @param parentTaskId The parentTaskId to set
     */
    public void setParentTaskId(Integer parentTaskId) {
        this.parentTaskId = parentTaskId;
    }

    /**
     * @return The created
     */
    public Date getCreated() {
        return created;
    }

    /**
     * @param created The created to set
     */
    public void setCreated(Date created) {
        this.created = created;
    }

    /**
     * @return The modified
     */
    public Date getModified() {
        return modified;
    }

    /**
     * @param modified The modified to set
     */
    public void setModified(Date modified) {
        this.modified = modified;
    }

    /**
     * @return The startDate
     */
    public Date getStartDate() {
        return startDate;
    }

    /**
     * @param startDate The startDate to set
     */
    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }

    /**
     * @return The dueDate
     */
    public Date getDueDate() {
        return dueDate;
    }

    /**
     * @param dueDate The dueDate to set
     */
    public void setDueDate(Date dueDate) {
        this.dueDate = dueDate;
    }

    /**
     * @return The order
     */
    public Integer getOrder() {
        return order;
    }

    /**
     * @param order The order to set
     */
    public void setOrder(Integer order) {
        this.order = order;
    }

    /**
     * @return The complete
     */
    public Boolean getComplete() {
        return complete;
    }

    /**
     * @param complete The complete to set
     */
    public void setComplete(Boolean complete) {
        this.complete = complete;
    }

    /**
     * @return Type of task.
     */
    public TaskStatus getStatus() {
        return status;
    }

    /**
     * @param defaultStatus Return this type if type == null.
     * @return Type of task.
     */
    public TaskStatus getStatus(TaskStatus defaultStatus) {
        if (status == null) {
            return defaultStatus;
        } else {
            return status;
        }
    }

    /**
     * @param status Type of task.
     */
    public void setStatus(TaskStatus status) {
        this.status = status;
    }

    /**
     * @return Number of sub tasks.
     */
    public Integer getNumberOfSubTasks() {
        return numberOfSubTasks;
    }

    /**
     * @return Number of all sub tasks.
     */
    public Integer getNumberOfAllSubTasks() {
        return numberOfSubTasks;
    }

    /**
     * Retrieve ID from cursor.
     * @param cursor Task query.
     * @return Retrieved ID.
     */
    public static int retrieveId(Cursor cursor) {
       return FULL_PROJECTION.getInteger(cursor, Task.Column.ID);
    }
}
